package com.cailu.rabmq.sender.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.cailu.common.constant.DelaySenderEessageCommon;

/**
 * @author cailu
 * @filename DelaySenderConfig
 * @description 延迟消费 配置在消息上
 * @date 2020/3/30 16:59
 */
@Configuration
public class DelaySenderEessageConfig {

	/**
	 * 在介绍具体的实现思路之前，我们先来介绍一下RabbitMQ的两个特性，
	 * 一个是Time-To-Live Extensions，另一个是Dead Letter Exchanges
	 * <p>
	 * Time-To-Live Extensions
	 * RabbitMQ允许我们为消息或者队列设置TTL（time to live），也就是过期时间
	 * TTL表明了一条消息可在队列中存活的最大时间，单位为毫秒
	 * 也就是说，当某条消息被设置了TTL或者当某条消息进入了设置了TTL的队列时,这条消息会在经过TTL秒后“死亡”，成为Dead Letter
	 * 如果既配置了消息的TTL，又配置了队列的TTL，那么较小的那个值会被取用
	 * <p>
	 * <p>
	 * Dead Letter Exchange
	 * 在RabbitMQ中，一共有三种消息的“死亡”形式
	 * * 消息被拒绝。通过调用basic.reject或者basic.nack并且设置的requeue参数为false。也就是：requeue=false
	 * * 消息因为设置了TTL而过期。
	 * * 消息进入了一条已经达到最大长度的队列
	 * 如果队列设置了Dead Letter Exchange（DLX），那么这些Dead Letter就会被重新publish到Dead Letter Exchange
	 * 通过Dead Letter Exchange路由到其他队列
	 */


	/**
	 * 案例
	 *
	 * 为了方便接下来的测试，我们将delay_queue_per_message_ttl以及delay_queue_per_queue_ttl的DLX配置分两个目录进行演示，
	 * 且过期的消息都会通过DLX转发到delay_process_queue
	 * */


	/**
	 * 功能描述  delay_queue_per_message_ttl TTL配置在【消息上】的缓冲队列
	 * @param
	 * @return org.springframework.amqp.core.Queue
	 * @author cailu
	 * @date 2020/3/30 17:11
	 */
	@Bean
	public Queue delayQueuePerMessageTTL() {

		return QueueBuilder.durable(DelaySenderEessageCommon.DELAY_EXCHANGE_QUEUE_TTL_NAME)

				//x-dead-letter-exchange	声明了队列里的死信转发到的DLX名称，
				//x-dead-letter-routing-key 声明了这些死信在转发时携带的DLK名称

				// DLX，dead letter发送到的exchange 延迟交换名称
				.withArgument("x-dead-letter-exchange", DelaySenderEessageCommon.DELAY_EXCHANGE_SLOW_NAME)
				// DLK dead letter携带的routing key 每个消息的延迟队列名称
				.withArgument("x-dead-letter-routing-key", DelaySenderEessageCommon.DELAY_EXCHANGE_QUEUE_NAME)
				.build();
	}


	/**
	 * 功能描述  首先，我们需要配置DLX
	 * @param
	 * @return org.springframework.amqp.core.DirectExchange
	 * @author cailu
	 * @date 2020/3/30 17:23
	 */
	@Bean
	DirectExchange delayExchange() {
		return new DirectExchange(DelaySenderEessageCommon.DELAY_EXCHANGE_SLOW_NAME);
	}

	/**
	 * 功能描述 delay_process_queue：实际消费队列
	 * @param
	 * @return org.springframework.amqp.core.Queue
	 * @author cailu
	 * @date 2020/3/30 17:22
	 */
	@Bean
	Queue delayProcessQueue() {
		return QueueBuilder.durable(DelaySenderEessageCommon.DELAY_EXCHANGE_QUEUE_NAME)
				.build();
	}


	/**
	 * 功能描述 然后再将该DLX绑定到实际消费队列即delay_process_queue上。
	 * 这样所有的死信都会通过DLX被转发到delay_process_queue：
	 * @param delayProcessQueue 延迟处理队列
	 * @param delayExchange     延迟交换
	 * @return org.springframework.amqp.core.Binding
	 * @author cailu
	 * @date 2020/3/30 17:23
	 */
	@Bean
	Binding dlxBinding(Queue delayProcessQueue, DirectExchange delayExchange) {
		return BindingBuilder.bind(delayProcessQueue)
				.to(delayExchange)
				.with(DelaySenderEessageCommon.DELAY_EXCHANGE_QUEUE_NAME);
	}
}
